package ChannelTutorial.Demo01;

import io.netty.bootstrap.Bootstrap;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.codec.string.StringDecoder;
import io.netty.handler.codec.string.StringEncoder;
import lombok.extern.slf4j.Slf4j;

/**
 * Demo01 - Channel 基础概念演示 - 客户端
 * 
 * 学习目标：
 * 1. 理解 NioSocketChannel 的作用
 * 2. 学习如何创建和使用客户端 Channel
 * 3. 了解 Channel 的基本操作
 */
@Slf4j
public class Client {

    public static void main(String[] args) {
        log.info("=== Channel 基础概念演示 - 客户端 ===\n");
        
        try {
            startClient();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 客户端：使用 NioSocketChannel
     * 
     * NioSocketChannel 的特点：
     * - 用于 TCP 连接的客户端和服务端通信
     * - 可以读写数据
     * - 代表一个实际的网络连接
     */
    private static void startClient() throws Exception {
        EventLoopGroup group = new NioEventLoopGroup();
        
        try {
            Bootstrap bootstrap = new Bootstrap();
            bootstrap.group(group)
                .channel(NioSocketChannel.class)  // 指定客户端 Channel 类型
                .handler(new ChannelInitializer<SocketChannel>() {
                    @Override
                    protected void initChannel(SocketChannel ch) throws Exception {
                        log.info("客户端：连接已建立");
                        
                        // 打印 Channel 的基本信息
                        printChannelInfo("客户端 Channel", ch);
                        
                        // 添加处理器
                        ch.pipeline().addLast(new StringDecoder());
                        ch.pipeline().addLast(new StringEncoder());
                        ch.pipeline().addLast(new ClientHandler());
                    }
                });
            
            // connect() 方法会创建并连接 NioSocketChannel
            ChannelFuture connectFuture = bootstrap.connect("localhost", 8080).sync();
            log.info("客户端：已连接到服务端 localhost:8080\n");
            
            // 获取客户端 Channel
            Channel clientChannel = connectFuture.channel();
            
            // 演示 Channel 的基本操作
            demonstrateChannelOperations(clientChannel);
            
            // 等待 3 秒后关闭
            Thread.sleep(3000);
            clientChannel.close().sync();
            
        } finally {
            group.shutdownGracefully();
        }
    }

    /**
     * 打印 Channel 的基本信息
     */
    private static void printChannelInfo(String name, Channel channel) {
        log.info("┌─────────────────────────────────────────");
        log.info("│ {} 信息：", name);
        log.info("│ Channel 类型: {}", channel.getClass().getSimpleName());
        log.info("│ Channel ID: {}", channel.id().asShortText());
        log.info("│ 本地地址: {}", channel.localAddress());
        log.info("│ 远程地址: {}", channel.remoteAddress());
        log.info("│ 是否激活(active): {}", channel.isActive());
        log.info("│ 是否打开(open): {}", channel.isOpen());
        log.info("│ 是否可写(writable): {}", channel.isWritable());
        log.info("│ 是否已注册(registered): {}", channel.isRegistered());
        log.info("└─────────────────────────────────────────\n");
    }

    /**
     * 演示 Channel 的基本操作
     */
    private static void demonstrateChannelOperations(Channel channel) {
        log.info("=== 演示 Channel 的基本操作 ===\n");
        
        // 1. 发送数据
        log.info("1. 发送数据：writeAndFlush()");
        channel.writeAndFlush("Hello, Netty Channel!");
        
        // 2. 获取 Pipeline
        log.info("2. 获取 Pipeline：channel.pipeline()");
        ChannelPipeline pipeline = channel.pipeline();
        log.info("   Pipeline: {}", pipeline);
        
        // 3. 获取 EventLoop
        log.info("3. 获取 EventLoop：channel.eventLoop()");
        EventLoop eventLoop = channel.eventLoop();
        log.info("   EventLoop: {}", eventLoop);
        
        // 4. 获取配置
        log.info("4. 获取配置：channel.config()");
        ChannelConfig config = channel.config();
        log.info("   接收缓冲区分配器: {}", config.getRecvByteBufAllocator().getClass().getSimpleName());
        log.info("   写缓冲区高水位: {} bytes", config.getWriteBufferHighWaterMark());
        log.info("   写缓冲区低水位: {} bytes", config.getWriteBufferLowWaterMark());
        
        // 5. 获取 ByteBuf 分配器
        log.info("5. 获取 ByteBuf 分配器：channel.alloc()");
        log.info("   ByteBuf 分配器: {}\n", channel.alloc().getClass().getSimpleName());
    }

    /**
     * 客户端处理器
     */
    static class ClientHandler extends ChannelInboundHandlerAdapter {
        
        @Override
        public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
            String message = (String) msg;
            log.info("客户端收到回复: {}", message);
        }

        @Override
        public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
            log.error("客户端异常：", cause);
            ctx.close();
        }
    }
}

/*
=== 运行结果分析 ===

1. NioSocketChannel：
   - 客户端和服务端通信的 Channel
   - 可以读写数据
   - 代表一个实际的 TCP 连接

2. Channel 的核心方法：
   - writeAndFlush()：写数据并刷新
   - pipeline()：获取处理链
   - eventLoop()：获取事件循环
   - config()：获取配置
   - alloc()：获取内存分配器

=== 关键知识点 ===

1. 客户端和服务端通信使用 NioSocketChannel
2. Channel 提供了丰富的方法来操作网络连接
3. 每个 Channel 都关联一个 Pipeline、EventLoop 和 Config
*/

